

/*
                                                         --> request
    requestor --> 进行请求管理 -- req_desc                --> RType
                                                         --> callback
                                                         --> response
*/

#pragma once
#include "../common/net.hpp"
#include "../common/message.hpp"
#include <future>
#include <mutex>
#include <functional>

namespace jsonrpc
{
    // 客户端和服务端的接口可能重合
    namespace client
    {
        class Requestor
        {
        public:
            using ptr = std::shared_ptr<Requestor>;
            using ReqCallBack = std::function<void(const BaseMessage::ptr&)>; 
            using AsyncResponse = std::future<BaseMessage::ptr>;
            struct ReqDescrible
            {
                using ptr = std::shared_ptr<ReqDescrible>;
                BaseMessage::ptr request;
                RType rtype;
                std::promise<BaseMessage::ptr> response; // 异步请求
                ReqCallBack callback; // 回调(拿到响应后直接调这个函数处理)
            };
            // 注册给Dispatcher, 拿响应
            void onResponse(const BaseConnection::ptr& conn, BaseMessage::ptr& msg)
            {
                std::string rid = msg->rid();
                ReqDescrible::ptr rid_desc = getDescrible(rid);
                if(rid_desc.get() == nullptr)
                {
                    ELOG("收到响应, 但是未找到对应的请求描述--%s",rid.c_str());
                    return;
                }
                // 根据类型做处理
                if(rid_desc->rtype == RType::REQ_ASYNC)
                {
                    rid_desc->response.set_value(msg);
                }
                else if(rid_desc->rtype == RType::REQ_CALLBACK)
                {
                    if(rid_desc->callback)rid_desc->callback(msg);
                }
                else
                {
                    ELOG("收到未知请求类型");
                }

                deleteDescrible(rid);
            }

            // 发送请求 -- 异步
            bool send(const BaseConnection::ptr& conn, const BaseMessage::ptr& req, AsyncResponse& async_rsp)
            {
                ReqDescrible::ptr rid_desc = newDescrible(req, RType::REQ_ASYNC);
                if(rid_desc.get() == nullptr)
                {
                    ELOG("构造失败请求描述对象失败");
                    return false;
                } 
                conn->send(req);
                async_rsp = rid_desc->response.get_future();
                return true;
            }
            // 发送请求 -- 同步
            bool send(const BaseConnection::ptr& conn, const BaseMessage::ptr& req, BaseMessage::ptr& rsp)
            {
                AsyncResponse rsp_future;
                bool ret = send(conn, req, rsp_future);
                if(ret == false)
                    return false;

                rsp = rsp_future.get(); //变为同步, 有结果就拿到, 没结果就阻塞
                return true;
            }

            // 发送请求 -- 回调
            bool send(const BaseConnection::ptr& conn, const BaseMessage::ptr& req, ReqCallBack& cb)
            {
                ReqDescrible::ptr rid_desc = newDescrible(req, RType::REQ_CALLBACK, cb);
                if(rid_desc.get() == nullptr)
                {
                    ELOG("构造失败请求描述对象失败");
                    return false;
                } 
                conn->send(req);
                return true;
            }
        private:
            ReqDescrible::ptr newDescrible(const BaseMessage::ptr& req, RType rtype, const ReqCallBack& cb = ReqCallBack())
            {
                std::unique_lock<std::mutex> lock(_mutex);
                ReqDescrible::ptr req_desc = std::make_shared<ReqDescrible>();
                req_desc->request = req; // 描述请求
                req_desc->rtype = rtype; // 描述请求类型
                if(rtype == RType::REQ_CALLBACK && cb)
                {
                    req_desc->callback = cb;
                }
                _request_desc.insert(std::make_pair(req->rid(), req_desc));
                return req_desc;
            }   
            // 根据请求id获取对应描述
            ReqDescrible::ptr getDescrible(const std::string& rid)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _request_desc.find(rid);
                if(it == _request_desc.end())
                {
                    ELOG("找不到对应请求描述: %s", rid.c_str());
                    return ReqDescrible::ptr();
                }
                return it->second;
            }
            // 删除请求描述
            void deleteDescrible(const std::string& rid)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _request_desc.erase(rid);
            }

        private:
            std::mutex _mutex;
            std::unordered_map<std::string, ReqDescrible::ptr> _request_desc; 
        };
    }
}